﻿///////////////////////////////////////////////////////////////////////////////////////////////
// System.Text.Parsing - © 2011 Sebastien Pellizzari
// Released under the MIT License (http://www.opensource.org/licenses/mit-license.php)
///////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace System.Text.Parsing
{
/*
    /// <summary>Represents a parser symbol.</summary>
    /// <typeparam name="TRange">The type of token range.</typeparam>
    /// <typeparam name="TValue">The type of value associated with a symbol.</typeparam>
    public struct ParserSymbol<TRange, TValue>
        where TRange : ITokenRange<TRange>
    {
        /// <summary>An integer representing the type of this symbol.</summary>
        /// <remarks>A negative value represents a non-terminal symbol. Value 1 is reserved for the ERROR token
        /// and 2 for the EOF token. Other positive values represent terminal tokens, as produced by the tokenizer.</remarks>
        public int SymbolTypeId;
        /// <summary>The value associated with this symbol.</summary>
        public TValue Value;
        /// <summary>The range of source data corresponding to this symbol.</summary>
        public TRange Range;
    }

    /// <summary>Represents the interface for an object that is used by a parser for callbacks.</summary>
    /// <typeparam name="TRange">The type of token range.</typeparam>
    /// <typeparam name="TSymbolValue">The type of symbol value.</typeparam>
    public interface IParserCallback<TRange, TSymbolValue>
            where TRange : ITokenRange<TRange>
    {
    }

    /// <summary>Represents the interface for an object that observes the work of a parser.</summary>
    /// <typeparam name="TRange">The type of token range.</typeparam>
    /// <typeparam name="TSymbolValue">The type of symbol value.</typeparam>
    public interface IParserObserver<TRange, TSymbolValue>
        where TRange : ITokenRange<TRange>
    {
    }

    /// <summary>Represents the internal tables of a parser's automaton.</summary>
    public sealed class ParserTable
    {
        /// <summary>Represents a rule definition.</summary>
        internal struct Rule
        {
            /// <summary>The left hand side symbol type ID.</summary>
            public readonly int LHS;
            /// <summary>The right hand side symbol type IDs.</summary>
            public readonly int[] RHS;

            /// <summary>Initializes a value of the <see cref="Rule"/> type.</summary>
            public Rule(int lhs, int[] rhs) { LHS = lhs; RHS = rhs; }
        }

        /// <summary>Represents a state definition.</summary>
        internal struct State
        {
            /// <summary>The default action code for that state.</summary>
            public readonly int DefaultAction;
            /// <summary>Determines whether the action table contains entries for tokens.</summary>
            public readonly bool CanShift;
            /// <summary>The action code table for that state.</summary>
            public readonly Dictionary<int, int> Table;

            /// <summary>Initializes a value of the <see cref="State"/> type.</summary>
            public State(int defaultAction, bool canShift, Dictionary<int, int> table) { DefaultAction = defaultAction; CanShift = canShift; Table = table; }
        }

        private readonly int _axiom;        // Axiom.
        private readonly Rule[] _rules;     // Array of rules.
        private readonly State[] _states;   // Array of states.

        /// <summary>Initializes an instance of the <see cref="ParserTable"/> class.</summary>
        internal ParserTable(int axiom, Rule[] rules, State[] states) { _axiom = axiom; _rules = rules; _states = states; }

        //-----------------------------------------------------------------------
        //     Properties
        //-----------------------------------------------------------------------

        /// <summary>Gets the symbol type ID of the axiom.</summary>
        internal int AxiomId { get { return _axiom; } }
        /// <summary>Gets the array of rules.</summary>
        internal Rule[] Rules { get { return _rules; } }
        /// <summary>Gets the array of states.</summary>
        internal State[] States { get { return _states; } }

        //-----------------------------------------------------------------------
        //     Public Members
        //-----------------------------------------------------------------------

        /// <summary>Reads a parser table from specified stream.</summary>
        /// <param name="stream">The stream to read the table from.</param>
        /// <returns>A <see cref="ParserTable"/> object.</returns>
        public static ParserTable CreateFromStream(Stream stream)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            if (!stream.CanRead) throw new InvalidOperationException("Specified stream does not support Read operation");
            var binaryReader = new BinaryReader(stream);
            var axiom = binaryReader.ReadInt32();
            var ruleCount = binaryReader.ReadInt32();
            var stateCount = binaryReader.ReadInt32();
            var rules = new Rule[ruleCount];
            var states = new State[stateCount];
            for (int i = 0; i < ruleCount; i++)
            {
                var lhs = binaryReader.ReadInt32();
                var rhsCount = binaryReader.ReadInt32();
                var rhs = new int[rhsCount];
                for (int j = 0; j < rhsCount; j++) rhs[j] = binaryReader.ReadInt32();
                rules[i] = new Rule(lhs, rhs);
            }
            for (int i = 0; i < stateCount; i++)
            {
                var defaultAction = binaryReader.ReadInt32();
                var canShift = binaryReader.ReadBoolean();
                var table = new Dictionary<int, int>();
                var tableElementCount = binaryReader.ReadInt32();
                for (int j = 0; j < tableElementCount; j++)
                {
                    var token = binaryReader.ReadInt32();
                    var action = binaryReader.ReadInt32();
                    table.Add(token, action);
                }
                states[i] = new State(defaultAction, canShift, table);
            }
            return new ParserTable(axiom, rules, states);
        }

        /// <summary>Reads a parser table from specified resource stream in specified assembly.</summary>
        /// <param name="assembly">The assembly containing the resource.</param>
        /// <param name="resourceName">The name of the resource.</param>
        /// <returns>A <see cref="ParserTable"/> object.</returns>
        public static ParserTable CreateFromResource(Assembly assembly, string resourceName)
        {
            if (assembly == null) throw new ArgumentNullException("assembly");
            if (resourceName == null) throw new ArgumentNullException("resourceName");
            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                if (stream == null) throw new KeyNotFoundException("Specified resource not found in specified assembly");
                return CreateFromStream(stream);
            }
        }
    }

    /// <summary>Represents a set of options for a parser.</summary>
    [Flags]
    public enum ParseOptions
    {
        /// <summary>Represents no options.</summary>
        None = 0,
        /// <summary>When the EOF token is encountered, the parser will abruptly stop in its current state. This option is useful
        /// for code completion implementers wanting to know in which state the parser is at a given point.</summary>
        StopAtEOF = 1,
    }

    /// <summary>Represents the result of a parse operation.</summary>
    public enum ParseResult
    {
        /// <summary>The parsing operation has not completed yet.</summary>
        NotCompleted,
        /// <summary>The parsing operation completed successfully.</summary>
        Success,
        /// <summary>The parsing operation encountered an error.</summary>
        Error,
        /// <summary>The parsing operation stopped when it encountered the EOF token.</summary>
        StoppedAtEOF,
    }

    /// <summary>Represents the base class of a parser.</summary>
    /// <typeparam name="TRange">The type of token range.</typeparam>
    /// <typeparam name="TTokenValue">The type of token value.</typeparam>
    /// <typeparam name="TTokenizer">The type of tokenizer.</typeparam>
    /// <typeparam name="TSymbolValue">The type of symbol value.</typeparam>
    /// <typeparam name="TCallback">The type of callback object.</typeparam>
    /// <typeparam name="TObserver">The type of observer object.</typeparam>
    public class Parser<TRange, TTokenValue, TTokenizer, TSymbolValue, TCallback, TObserver> : ITokenizerContext
        where TRange : ITokenRange<TRange>
        where TCallback : IParserCallback<TRange, TSymbolValue>
        where TObserver : IParserObserver<TRange, TSymbolValue>
        where TTokenizer : ITokenizer<TRange, TTokenValue>
    {
        private ParserTable _table;     // The parser table.
        private TCallback _callback;    // The callback object.
        private TObserver _observer;    // The observer object.
        private TTokenizer _tokenizer;  // The tokenizer object.

        // StackItem struct.
        private struct StackItem
        {
            public int StateIndex;                              // State index.
            public ParserSymbol<TRange, TSymbolValue> Symbol;   // Symbol.
        }

        private int _stateIndex;                        // Index of current state.
        private int _stackIndex;                        // Current index in stack.
        private bool _initialized;                      // Has the parser been initialized?
        private StackItem[] _stack;                     // Current state stack.
        private ParseOptions _options;                  // Parse options.
        private Token<TRange, TTokenValue> _nextToken;  // Next token.
        
        private int _axiomId;                   // Axiom ID.
        private ParserTable.Rule[] _rules;      // Rule table.
        private ParserTable.State[] _states;    // State table.

        //-----------------------------------------------------------------------
        //     Constructors
        //-----------------------------------------------------------------------

        /// <summary>Initializes an instance of the <see cref="Parser"/> class.</summary>
        public Parser()
        {
            _stack = new StackItem[64]; 
        }

        //-----------------------------------------------------------------------
        //     Properties
        //-----------------------------------------------------------------------

        /// <summary>Gets or sets the generated parser table.</summary>
        public ParserTable Table { get { return _table; } set { _table = value; } }
        /// <summary>Gets or sets the optional callback object.</summary>
        public TCallback Callback { get { return _callback; } set { _callback = value; } }
        /// <summary>Gets or sets the optional observer object.</summary>
        public TObserver Observer { get { return _observer; } set { _observer = value; } }
        /// <summary>Gets or sets the tokenizer object used to scan tokens.</summary>
        public TTokenizer Tokenizer { get { return _tokenizer; } set { _tokenizer = value; } }

        //-----------------------------------------------------------------------
        //     Methods
        //-----------------------------------------------------------------------

        /// <summary>Parses tokens from specified tokenizer using specified table until an EOF token is encountered.</summary>
        /// <param name="options">A set of parsing options.</param>
        /// <returns>A member of the <see cref="ParseResult"/> enumeration.</returns>
        public ParseResult Parse(ParseOptions options)
        {
            ParseInitialize(options);
            for (; ; )
            {
                var result = ParseStep();
                if (result != ParseResult.NotCompleted) return result;
            }
        }

        /// <summary>Initializes the parsing operation.</summary>
        /// <param name="options">A set of parsing options.</param>
        public void ParseInitialize(ParseOptions options)
        {
            // Check.
            if (_table == null) throw new InvalidOperationException("No parser table specified");
            if (_tokenizer == null) throw new InvalidOperationException("No tokenizer specified");

            // Save things.
            _options = options;
            _axiomId = _table.AxiomId;
            _rules = _table.Rules;
            _states = _table.States;

            // Start with state #0.
            _stateIndex = 0;

            // Initialize stack.
            _stackIndex = 0;
            _stack[0].StateIndex = _stateIndex;

            // Initialize tokens.
            _nextToken.TypeId = int.MinValue;

            // We're initialized.
            _initialized = true;
        }

        /// <summary>Performs a parsing step.</summary>
        /// <returns>The current status of the parsing operation.</returns>
        public ParseResult ParseStep()
        {
            if (!_initialized) throw new InvalidOperationException("Parser is not initialized");

            int action;

            // If current state has Token -> Action entries...
            if (_states[_stateIndex].CanShift)
            {
                // If we have scanned no tokens...
                if (_nextToken.TypeId == int.MinValue)
                {
                    // Scan tokens until they're not ignored anymore.
                    do
                    {
                        // Scan a new token.
                        _tokenizer.Scan(this, out _nextToken);

                        // If the token is expected by the parser, don't ignore it.
                        if (IsExpected(_nextToken.TypeId)) _nextToken.Ignore = false;

                    } while (_nextToken.Ignore);

                    // If we reached the end of input...
                    if (_nextToken.TypeId == TokenTypeIds.EOF && (_options & ParseOptions.StopAtEOF) == ParseOptions.StopAtEOF)
                    {
                        // Stop here.
                        return ParseResult.StoppedAtEOF;
                    }
                }

                // Try to find a transition for that token.
                if (!_states[_stateIndex].Table.TryGetValue(_nextToken.TypeId, out action))
                    action = _states[_stateIndex].DefaultAction;

                // Prevent any SHIFT action if this is an error token.
                if (_nextToken.TypeId == TokenTypeIds.Error && action > 0) action = 0;
            }
            else
            {
                // Use the default action code.
                action = _states[_stateIndex].DefaultAction;
            }

            // If it's a SHIFT action...
            if (action > 0)
            {
                // Shift.
                Shift(action);
            }
            // If it's a REDUCE action...
            else if (action < 0)
            {
                // Reduce.
                Reduce(-action);

                // If it's a HALT...
                if (action == -_axiomId)
                {
                    // We successfully reached the axiom.
                    return ParseResult.Success;
                }
            }
            // It's an ERROR.
            else
            {
                // If we reached the end of input...
                if (_nextToken.TypeId == TokenTypeIds.EOF && (_options & ParseOptions.StopAtEOF) == ParseOptions.StopAtEOF)
                {
                    // Stop here.
                    return ParseResult.StoppedAtEOF;
                }

                // Try to recover.
                if (!ErrorRecovery())
                {
                    // The source data contains errors.
                    return ParseResult.Error;
                }
            }
        }

        //-----------------------------------------------------------------------
        //     Non Public
        //-----------------------------------------------------------------------

        // IsExpected method.
        bool ITokenizerContext.IsExpected(int tokenTypeId)
        {
            if (tokenTypeId >= TokenTypeIds.User && _states[_stateIndex].CanShift)
            {
                int action;
                if (_states[_stateIndex].Table.TryGetValue(tokenTypeId, out action))
                    return action > 0; // Only if it's a SHIFT action.
            }
            return false;
        }

        // Shift method.
        private void Shift(int stateIndex)
        {
            // Jump to specified state.
            //_stack[_stackIndex].

            // Make the stack grow.
            StackGrow(1);
        }

        private void StackGrow(int count)
        {
            throw new NotImplementedException();
        }
    }
*/
}
